package com.sky.skyopsserver.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sky.skyopsserver.aspect.ApiOperationLog;
import com.sky.skyopsserver.service.ApplicationService;
import com.sky.skyopsserver.utils.PageResponse;
import com.sky.skyopsserver.utils.Response;
import com.sky.skyopsserver.vos.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 应用信息控制器
 * 
 * @author Administrator
 * @since 2025-01-17
 */
@Slf4j
@RestController
@RequestMapping("/api/application")
@RequiredArgsConstructor
@Validated
@Tag(name = "应用管理", description = "应用信息的增删改查操作")
public class ApplicationController {

    private final ApplicationService applicationService;

    /**
     * 添加应用
     * 
     * @param reqVO 添加应用请求VO
     * @return 应用ID
     */
    @PostMapping("/add")
    @Operation(summary = "添加应用", description = "新增一个应用信息")
    @ApiOperationLog(description = "添加应用")
    public Response<Long> addApplication(@Valid @RequestBody ApplicationAddReqVO reqVO) {
        Long applicationId = applicationService.addApplication(reqVO);
        return Response.success(applicationId);
    }

    /**
     * 更新应用信息
     * 
     * @param reqVO 更新应用请求VO
     * @return 操作结果
     */
    @PutMapping("/update")
    @Operation(summary = "更新应用信息", description = "修改应用的基本信息")
    @ApiOperationLog(description = "更新应用信息")
    public Response<Boolean> updateApplication(@Valid @RequestBody ApplicationUpdateReqVO reqVO) {
        Boolean result = applicationService.updateApplication(reqVO);
        return Response.success(result);
    }

    /**
     * 删除应用
     * 
     * @param id 应用ID
     * @return 操作结果
     */
    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除应用", description = "根据ID删除指定应用")
    @ApiOperationLog(description = "删除应用")
    public Response<Boolean> deleteApplication(
            @Parameter(description = "应用ID", required = true)
            @PathVariable("id") @NotNull(message = "应用ID不能为空") @Positive(message = "应用ID必须为正数") Long id) {
        Boolean result = applicationService.deleteApplication(id);
        return Response.success(result);
    }

    /**
     * 批量删除应用
     * 
     * @param ids 应用ID列表
     * @return 操作结果
     */
    @DeleteMapping("/batch-delete")
    @Operation(summary = "批量删除应用", description = "根据ID列表批量删除应用")
    @ApiOperationLog(description = "批量删除应用")
    public Response<Boolean> batchDeleteApplication(
            @Parameter(description = "应用ID列表", required = true)
            @RequestBody @NotEmpty(message = "应用ID列表不能为空") List<@Positive(message = "应用ID必须为正数") Long> ids) {
        Boolean result = applicationService.batchDeleteApplication(ids);
        return Response.success(result);
    }

    /**
     * 根据ID查询应用详情
     * 
     * @param id 应用ID
     * @return 应用详情
     */
    @GetMapping("/detail/{id}")
    @Operation(summary = "查询应用详情", description = "根据ID获取应用的详细信息")
    @ApiOperationLog(description = "查询应用详情")
    public Response<ApplicationRspVO> getApplicationById(
            @Parameter(description = "应用ID", required = true)
            @PathVariable("id") @NotNull(message = "应用ID不能为空") @Positive(message = "应用ID必须为正数") Long id) {
        ApplicationRspVO result = applicationService.getApplicationById(id);
        return Response.success(result);
    }

    /**
     * 根据编码查询应用
     * 
     * @param code 应用编码
     * @return 应用信息
     */
    @GetMapping("/detail/code/{code}")
    @Operation(summary = "根据编码查询应用", description = "根据应用编码获取应用信息")
    @ApiOperationLog(description = "根据编码查询应用")
    public Response<ApplicationRspVO> getApplicationByCode(
            @Parameter(description = "应用编码", required = true)
            @PathVariable("code") @NotBlank(message = "应用编码不能为空") String code) {
        ApplicationRspVO result = applicationService.getApplicationByCode(code);
        return Response.success(result);
    }

    /**
     * 分页查询应用列表
     * 
     * @param reqVO 分页查询请求VO
     * @return 分页结果
     */
    @PostMapping("/page")
    @Operation(summary = "分页查询应用列表", description = "根据条件分页查询应用信息")
    @ApiOperationLog(description = "分页查询应用列表")
    public PageResponse<ApplicationRspVO> getApplicationPage(@Valid @RequestBody ApplicationPageReqVO reqVO) {
        IPage<ApplicationRspVO> page = applicationService.getApplicationPage(reqVO);
        return PageResponse.success(page, page.getRecords());
    }

    /**
     * 查询所有应用选项（用于下拉选择）
     * 
     * @return 应用选项列表
     */
    @GetMapping("/options")
    @Operation(summary = "查询应用选项", description = "获取所有应用的选项列表，用于下拉选择")
    @ApiOperationLog(description = "查询应用选项")
    public Response<List<ApplicationOptionRspVO>> getAllApplicationOptions() {
        List<ApplicationOptionRspVO> result = applicationService.getAllApplicationOptions();
        return Response.success(result);
    }

    /**
     * 根据项目ID查询应用选项
     * 
     * @param projectId 项目ID
     * @return 应用选项列表
     */
    @GetMapping("/options/project/{projectId}")
    @Operation(summary = "按项目查询应用选项", description = "根据项目ID获取应用选项列表")
    @ApiOperationLog(description = "按项目查询应用选项")
    public Response<List<ApplicationOptionRspVO>> getApplicationOptionsByProjectId(
            @Parameter(description = "项目ID", required = true)
            @PathVariable("projectId") @NotNull(message = "项目ID不能为空") @Positive(message = "项目ID必须为正数") Long projectId) {
        List<ApplicationOptionRspVO> result = applicationService.getApplicationOptionsByProjectId(projectId);
        return Response.success(result);
    }

    /**
     * 获取应用统计信息
     * 
     * @return 应用统计信息
     */
    @GetMapping("/statistics")
    @Operation(summary = "获取应用统计信息", description = "获取应用的各项统计数据")
    @ApiOperationLog(description = "获取应用统计信息")
    public Response<ApplicationStatisticsRspVO> getApplicationStatistics() {
        ApplicationStatisticsRspVO result = applicationService.getApplicationStatistics();
        return Response.success(result);
    }

    /**
     * 检查应用编码是否已存在
     * 
     * @param code 应用编码
     * @param excludeId 排除的应用ID（可选）
     * @return 是否存在
     */
    @GetMapping("/check-code")
    @Operation(summary = "检查应用编码", description = "检查应用编码是否已存在")
    @ApiOperationLog(description = "检查应用编码")
    public Response<Boolean> checkApplicationCodeExists(
            @Parameter(description = "应用编码", required = true)
            @RequestParam("code") @NotBlank(message = "应用编码不能为空") String code,
            @Parameter(description = "排除的应用ID")
            @RequestParam(value = "excludeId", required = false) Long excludeId) {
        Boolean result = applicationService.checkApplicationCodeExists(code, excludeId);
        return Response.success(result);
    }

    /**
     * 检查应用名称是否已存在
     * 
     * @param name 应用名称
     * @param excludeId 排除的应用ID（可选）
     * @return 是否存在
     */
    @GetMapping("/check-name")
    @Operation(summary = "检查应用名称", description = "检查应用名称是否已存在")
    @ApiOperationLog(description = "检查应用名称")
    public Response<Boolean> checkApplicationNameExists(
            @Parameter(description = "应用名称", required = true)
            @RequestParam("name") @NotBlank(message = "应用名称不能为空") String name,
            @Parameter(description = "排除的应用ID")
            @RequestParam(value = "excludeId", required = false) Long excludeId) {
        Boolean result = applicationService.checkApplicationNameExists(name, excludeId);
        return Response.success(result);
    }

    /**
     * 根据名称模糊查询应用
     * 
     * @param name 应用名称关键字
     * @return 应用列表
     */
    @GetMapping("/search/name")
    @Operation(summary = "按名称搜索应用", description = "根据应用名称关键字模糊查询应用")
    @ApiOperationLog(description = "按名称搜索应用")
    public Response<List<ApplicationRspVO>> searchApplicationByName(
            @Parameter(description = "应用名称关键字", required = true)
            @RequestParam("name") @NotBlank(message = "应用名称关键字不能为空") String name) {
        List<ApplicationRspVO> result = applicationService.searchApplicationByName(name);
        return Response.success(result);
    }

    /**
     * 根据编码模糊查询应用
     * 
     * @param code 应用编码关键字
     * @return 应用列表
     */
    @GetMapping("/search/code")
    @Operation(summary = "按编码搜索应用", description = "根据应用编码关键字模糊查询应用")
    @ApiOperationLog(description = "按编码搜索应用")
    public Response<List<ApplicationRspVO>> searchApplicationByCode(
            @Parameter(description = "应用编码关键字", required = true)
            @RequestParam("code") @NotBlank(message = "应用编码关键字不能为空") String code) {
        List<ApplicationRspVO> result = applicationService.searchApplicationByCode(code);
        return Response.success(result);
    }

    /**
     * 验证应用编码格式
     * 
     * @param code 应用编码
     * @return 是否有效
     */
    @GetMapping("/validate-code")
    @Operation(summary = "验证应用编码格式", description = "验证应用编码是否符合格式要求")
    @ApiOperationLog(description = "验证应用编码格式")
    public Response<Boolean> validateApplicationCode(
            @Parameter(description = "应用编码", required = true)
            @RequestParam("code") @NotBlank(message = "应用编码不能为空") String code) {
        Boolean result = applicationService.validateApplicationCode(code);
        return Response.success(result);
    }

    /**
     * 获取所有应用编码列表
     * 
     * @return 应用编码列表
     */
    @GetMapping("/codes")
    @Operation(summary = "获取应用编码列表", description = "获取所有应用的编码列表")
    @ApiOperationLog(description = "获取应用编码列表")
    public Response<List<String>> getAllApplicationCodes() {
        List<String> result = applicationService.getAllApplicationCodes();
        return Response.success(result);
    }

    /**
     * 获取所有应用名称列表
     * 
     * @return 应用名称列表
     */
    @GetMapping("/names")
    @Operation(summary = "获取应用名称列表", description = "获取所有应用的名称列表")
    @ApiOperationLog(description = "获取应用名称列表")
    public Response<List<String>> getAllApplicationNames() {
        List<String> result = applicationService.getAllApplicationNames();
        return Response.success(result);
    }

    /**
     * 根据项目ID获取应用数量
     * 
     * @param projectId 项目ID
     * @return 应用数量
     */
    @GetMapping("/count/project/{projectId}")
    @Operation(summary = "获取项目应用数量", description = "获取指定项目下的应用数量")
    @ApiOperationLog(description = "获取项目应用数量")
    public Response<Long> getApplicationCountByProjectId(
            @Parameter(description = "项目ID", required = true)
            @PathVariable("projectId") @NotNull(message = "项目ID不能为空") @Positive(message = "项目ID必须为正数") Long projectId) {
        Long result = applicationService.getApplicationCountByProjectId(projectId);
        return Response.success(result);
    }

    /**
     * 移动应用到指定项目
     * 
     * @param applicationIds 应用ID列表
     * @param targetProjectId 目标项目ID
     * @return 操作结果
     */
    @PostMapping("/move-to-project")
    @Operation(summary = "移动应用到项目", description = "将指定应用移动到目标项目")
    @ApiOperationLog(description = "移动应用到项目")
    public Response<Boolean> moveApplicationsToProject(
            @Parameter(description = "应用ID列表", required = true)
            @RequestParam("applicationIds") @NotEmpty(message = "应用ID列表不能为空") List<@Positive(message = "应用ID必须为正数") Long> applicationIds,
            @Parameter(description = "目标项目ID", required = true)
            @RequestParam("targetProjectId") @NotNull(message = "目标项目ID不能为空") @Positive(message = "目标项目ID必须为正数") Long targetProjectId) {
        Boolean result = applicationService.moveApplicationsToProject(applicationIds, targetProjectId);
        return Response.success(result);
    }

    /**
     * 复制应用到指定项目
     * 
     * @param applicationId 应用ID
     * @param targetProjectId 目标项目ID
     * @param newCode 新应用编码
     * @param newName 新应用名称
     * @return 新应用ID
     */
    @PostMapping("/copy-to-project")
    @Operation(summary = "复制应用到项目", description = "将指定应用复制到目标项目")
    @ApiOperationLog(description = "复制应用到项目")
    public Response<Long> copyApplicationToProject(
            @Parameter(description = "应用ID", required = true)
            @RequestParam("applicationId") @NotNull(message = "应用ID不能为空") @Positive(message = "应用ID必须为正数") Long applicationId,
            @Parameter(description = "目标项目ID", required = true)
            @RequestParam("targetProjectId") @NotNull(message = "目标项目ID不能为空") @Positive(message = "目标项目ID必须为正数") Long targetProjectId,
            @Parameter(description = "新应用编码", required = true)
            @RequestParam("newCode") @NotBlank(message = "新应用编码不能为空") String newCode,
            @Parameter(description = "新应用名称", required = true)
            @RequestParam("newName") @NotBlank(message = "新应用名称不能为空") String newName) {
        Long result = applicationService.copyApplicationToProject(applicationId, targetProjectId, newCode, newName);
        return Response.success(result);
    }

    /**
     * 获取项目下的应用列表
     * 
     * @param projectId 项目ID
     * @return 应用列表
     */
    @GetMapping("/list/project/{projectId}")
    @Operation(summary = "获取项目应用列表", description = "获取指定项目下的所有应用")
    @ApiOperationLog(description = "获取项目应用列表")
    public Response<List<ApplicationRspVO>> getApplicationsByProjectId(
            @Parameter(description = "项目ID", required = true)
            @PathVariable("projectId") @NotNull(message = "项目ID不能为空") @Positive(message = "项目ID必须为正数") Long projectId) {
        List<ApplicationRspVO> result = applicationService.getApplicationsByProjectId(projectId);
        return Response.success(result);
    }

    /**
     * 获取空项目列表（没有应用的项目）
     * 
     * @return 项目ID列表
     */
    @GetMapping("/empty-projects")
    @Operation(summary = "获取空项目列表", description = "获取没有应用的项目ID列表")
    @ApiOperationLog(description = "获取空项目列表")
    public Response<List<Long>> getEmptyProjectIds() {
        List<Long> result = applicationService.getEmptyProjectIds();
        return Response.success(result);
    }

    /**
     * 获取有应用的项目列表
     * 
     * @return 项目ID列表
     */
    @GetMapping("/projects-with-apps")
    @Operation(summary = "获取有应用的项目列表", description = "获取包含应用的项目ID列表")
    @ApiOperationLog(description = "获取有应用的项目列表")
    public Response<List<Long>> getProjectIdsWithApplications() {
        List<Long> result = applicationService.getProjectIdsWithApplications();
        return Response.success(result);
    }
}